#include <boost/asio.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/write.hpp>
#include <future>
#include <iostream>
#include <memory>
#include <string>

int main(int argc, char *argv[]) {
  try {
    if (argc != 2) {
      std::cerr << "Usage: echo_client <port>\n";
      return 1;
    }
    boost::asio::io_context io;
    boost::asio::ip::tcp::socket sock(io);
    sock.connect(boost::asio::ip::tcp::endpoint(
        boost::asio::ip::address::from_string("127.0.0.1"), atoi(argv[1])));

    auto work = boost::asio::make_work_guard(io);
    std::thread thread([&io]() { io.run(); });
    while (true) {
      // 异步读取输入
      std::future<std::string> input_future =
          std::async(std::launch::async, []() {
            std::string input;
            std::getline(std::cin, input);
            return input;
          });
      std::cout << "#### " << __LINE__ << std::endl;
      // 等待输入
      std::string input = input_future.get();
      std::cout << "#### " << __LINE__ << std::endl;

      // 异步写入
      std::future<std::size_t> write_n = sock.async_write_some(
          boost::asio::buffer(input), boost::asio::use_future);
      std::cout << "#### " << __LINE__ << std::endl;

      // 等待写操作完成
      write_n.get();
      // if (write_n.wait_for(std::chrono::milliseconds(100)) ==
      //     std::future_status::timeout) {
      //   std::cout << "### wait timeout ###" << std::endl;
      // }
      std::cout << "#### " << __LINE__ << std::endl;

      // 异步读取
      char buf[0xFF];
      memset(buf, 0, sizeof(buf));
      std::cout << "#### " << __LINE__ << std::endl;
      std::future<std::size_t> read_n = sock.async_read_some(
          boost::asio::buffer(buf, 0xFF), boost::asio::use_future);
      std::cout << "#### " << __LINE__ << std::endl;

      // 等待读操作完成
      read_n.get();
      // if (read_n.wait_for(std::chrono::milliseconds(100)) ==
      //     std::future_status::timeout) {
      //   std::cout << "### wait timeout ###" << std::endl;
      // }
      std::cout << "#### " << __LINE__ << std::endl;

      // 输出结果
      std::cout << buf << std::endl;
    }
    io.stop();
    thread.join();
  } catch (const std::exception &e) {
    std::cerr << "Exception: " << e.what() << "\n";
    return 1;
  }
  return 0;
}